/*
 * Copyright (c) 2012 swing-on-fire Team
 * 
 * This file is part of Swing-On-Fire (http://code.google.com/p/swing-on-fire), licensed under the terms of the MIT
 * License (MIT).
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package com.google.code.swingonfire.component.page.old;

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;

import com.google.code.swingonfire.graphic.Path2DHelper;
import com.google.code.swingonfire.utility.interpolation.Interpolation;
import com.google.code.swingonfire.utility.interpolation.Interpolations;

public class JPageTransition
{

    private Interpolation alphaInterpolation;
    private double alphaStart;
    private double alphaEnd;
    private Interpolation moveInterpolation;
    private Path2D movePath;
    private Interpolation rotationInterpolation;
    private double rotationThetaStart;
    private double rotationThetaEnd;
    private Interpolation scaleInterpolation;
    private double scaleStart;
    private double scaleEnd;

    private double alpha = 1;
    private double move = 0;
    private double rotationTheta = 0;
    private double scale = 1;

    private Path2DHelper movePathHelper;
    private int movePathHelperWidth = 0;
    private int movePathHelperHeight = 0;

    public JPageTransition()
    {
        super();
    }

    public JPageTransition fadeOut()
    {
        return fadeOut(Interpolations.soft());
    }

    public JPageTransition fadeOut(Interpolation alphaInterpolation)
    {
        return alpha(alphaInterpolation, 1, 0);
    }

    public JPageTransition fadeIn()
    {
        return fadeIn(Interpolations.soft());
    }

    public JPageTransition fadeIn(Interpolation alphaInterpolation)
    {
        return alpha(alphaInterpolation, 0, 1);
    }

    public JPageTransition alpha(Interpolation alphaInterpolation, double alphaStart, double alphaEnd)
    {
        this.alphaInterpolation = alphaInterpolation;
        this.alphaStart = alphaStart;
        this.alphaEnd = alphaEnd;

        return this;
    }

    public JPageTransition moveInFromLeft(double widthFactor)
    {
        return moveInFromLeft(Interpolations.soft(), widthFactor);
    }

    public JPageTransition moveInFromLeft(Interpolation moveInterpolation, double widthFactor)
    {
        return move(moveInterpolation, -widthFactor, 0, 0, 0);
    }

    public JPageTransition moveInFromRight(double widthFactor)
    {
        return moveInFromRight(Interpolations.soft(), widthFactor);
    }

    public JPageTransition moveInFromRight(Interpolation moveInterpolation, double widthFactor)
    {
        return move(moveInterpolation, widthFactor, 0, 0, 0);
    }

    public JPageTransition moveInFromTop(double heightFactor)
    {
        return moveInFromTop(Interpolations.soft(), heightFactor);
    }

    public JPageTransition moveInFromTop(Interpolation moveInterpolation, double heightFactor)
    {
        return move(moveInterpolation, 0, -heightFactor, 0, 0);
    }

    public JPageTransition moveInFromBottom(double heightFactor)
    {
        return moveInFromBottom(Interpolations.soft(), heightFactor);
    }

    public JPageTransition moveInFromBottom(Interpolation moveInterpolation, double heightFactor)
    {
        return move(moveInterpolation, 0, heightFactor, 0, 0);
    }

    public JPageTransition moveIn(double widthFactor, double heightFactor)
    {
        return moveIn(Interpolations.accurate(), widthFactor, heightFactor);
    }

    public JPageTransition moveIn(Interpolation moveInterpolation, double widthFactor, double heightFactor)
    {
        return move(moveInterpolation, widthFactor, heightFactor, 0, 0);
    }

    public JPageTransition moveOutToLeft(double widthFactor)
    {
        return moveOutToLeft(Interpolations.soft(), widthFactor);
    }

    public JPageTransition moveOutToLeft(Interpolation moveInterpolation, double widthFactor)
    {
        return move(moveInterpolation, 0, 0, -widthFactor, 0);
    }

    public JPageTransition moveOutToRight(double widthFactor)
    {
        return moveOutToRight(Interpolations.soft(), widthFactor);
    }

    public JPageTransition moveOutToRight(Interpolation moveInterpolation, double widthFactor)
    {
        return move(moveInterpolation, 0, 0, widthFactor, 0);
    }

    public JPageTransition moveOutToTop(double widthFactor)
    {
        return moveOutToTop(Interpolations.soft(), widthFactor);
    }

    public JPageTransition moveOutToTop(Interpolation moveInterpolation, double heightFactor)
    {
        return move(moveInterpolation, 0, 0, 0, -heightFactor);
    }

    public JPageTransition moveOutToBottom(double widthFactor)
    {
        return moveOutToBottom(Interpolations.soft(), widthFactor);
    }

    public JPageTransition moveOutToBottom(Interpolation moveInterpolation, double heightFactor)
    {
        return move(moveInterpolation, 0, 0, 0, heightFactor);
    }

    public JPageTransition moveOut(double widthFactor, double heightFactor)
    {
        return moveOut(Interpolations.accurate(), widthFactor, heightFactor);
    }

    public JPageTransition moveOut(Interpolation moveInterpolation, double widthFactor, double heightFactor)
    {
        return move(moveInterpolation, 0, 0, widthFactor, heightFactor);
    }

    public JPageTransition move(Interpolation moveInterpolation, double fromX, double fromY, double toX, double toY)
    {
        Path2D movePath = new Path2D.Double();
        movePath.moveTo(fromX, fromY);
        movePath.lineTo(toX, toY);

        return move(moveInterpolation, movePath);
    }

    public JPageTransition move(Interpolation moveInterpolation, Path2D movePath)
    {
        this.moveInterpolation = moveInterpolation;
        this.movePath = movePath;

        return this;
    }

    public JPageTransition rotate(double times)
    {
        return rotate(Interpolations.accurate(), times);
    }

    public JPageTransition rotate(Interpolation rotationInterpolation, double times)
    {
        return rotate(rotationInterpolation, Math.PI * 2 * times, 0);
    }

    public JPageTransition rotate(Interpolation rotationInterpolation, double rotationThetaStart,
        double rotationThetaEnd)
    {
        this.rotationInterpolation = rotationInterpolation;
        this.rotationThetaStart = rotationThetaStart;
        this.rotationThetaEnd = rotationThetaEnd;

        return this;
    }

    public JPageTransition scaleToFit(double scale)
    {
        return scale(Interpolations.accurate(), scale, 1);
    }

    public JPageTransition scaleToFit(Interpolation scaleInterpolation, double scale)
    {
        return scale(scaleInterpolation, scale, 1);
    }

    public JPageTransition scale(Interpolation scaleInterpolation, double scaleStart, double scaleEnd)
    {
        this.scaleInterpolation = scaleInterpolation;
        this.scaleStart = scaleStart;
        this.scaleEnd = scaleEnd;

        return this;
    }

    public Interpolation getAlphaInterpolation()
    {
        return alphaInterpolation;
    }

    public double getAlphaStart()
    {
        return alphaStart;
    }

    public double getAlphaEnd()
    {
        return alphaEnd;
    }

    public Interpolation getMoveInterpolation()
    {
        return moveInterpolation;
    }

    public Path2D getMovePath()
    {
        return movePath;
    }

    public Interpolation getRotationInterpolation()
    {
        return rotationInterpolation;
    }

    public double getRotationThetaStart()
    {
        return rotationThetaStart;
    }

    public double getRotationThetaEnd()
    {
        return rotationThetaEnd;
    }

    public Interpolation getScaleInterpolation()
    {
        return scaleInterpolation;
    }

    public double getScaleStart()
    {
        return scaleStart;
    }

    public double getScaleEnd()
    {
        return scaleEnd;
    }

    public void reset()
    {
        step(0, 0, 0);
    }

    public void step(double duration, double time, double fraction)
    {
        if (alphaInterpolation != null)
        {
            alpha = alphaStart + ((alphaEnd - alphaStart) * alphaInterpolation.calculate(fraction));
        }
        else
        {
            alpha = 1;
        }

        if (moveInterpolation != null)
        {
            move = moveInterpolation.calculate(fraction);
        }
        else
        {
            move = 0;
        }

        if (rotationInterpolation != null)
        {
            rotationTheta =
                rotationThetaStart
                    + ((rotationThetaEnd - rotationThetaStart) * rotationInterpolation.calculate(fraction));
        }
        else
        {
            rotationTheta = 0;
        }

        if (scaleInterpolation != null)
        {
            scale = scaleStart + ((scaleEnd - scaleStart) * scaleInterpolation.calculate(fraction));
        }
        else
        {
            scale = 1;
        }
    }

    public void render(Graphics2D g, Image image, int width, int height)
    {
        g.translate(width / 2, height / 2);

        if (movePath != null)
        {
            if ((movePathHelper == null) || (width != movePathHelperWidth) || (height != movePathHelperHeight))
            {
                movePathHelper = new Path2DHelper(movePath, AffineTransform.getScaleInstance(width, height), 10);
                movePathHelperWidth = width;
                movePathHelperHeight = height;
            }

            Point2D point = movePathHelper.getPointByNormalizedDistance(move);

            g.translate(point.getX(), point.getY());
        }

        if (rotationTheta != 0)
        {
            g.rotate(rotationTheta);
        }

        if (scale != 1)
        {
            g.scale(scale, scale);
        }

        g.translate(-image.getWidth(null) / 2, -image.getHeight(null) / 2);

        if ((alpha >= 0) && (alpha < 1))
        {
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) alpha));
        }

        g.drawImage(image, 0, 0, null);
    }
}
